#!/usr/local/bin/python
# coding: utf-8
import zlib, pickle, re
import logging
from google.appengine.api import urlfetch
from google.appengine.runtime import apiproxy_errors
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app


def encrypt_rsa(key,data):
    return data

def decrypt_rsa(key,data):
    return data

def encrypt_fast(data):
    return "0", zlib.compress(data)

def decrypt_fast(key,data):
    return zlib.decompress(data)

class MainHandler(webapp.RequestHandler):
    RSA_KEY= ""
    SERVER_ID= "WallProxy/4.0"
    RETRY_FETCH= 3
    SKIPHEAD_REQUEST= [
        'connection', 'keep-alive', 'proxy-authenticate', 'proxy-connection',
        'proxy-authorization', 'te', 'trailers',
        'transfer-encoding', 'upgrade', 'host']
    SKIPHEAD_RESPONSE= ['connection','keep-alive','te','upgrade','transfer-encoding']
         
    def report(self, code, message):
        headers= {"content-type":"text/html", "server":MainHandler.SERVER_ID}
        content= """
            <html><head>
                <title>Tohr Router Error</title>
                </head><body>
                <h1>Tohr Router Error</h1>
                <p>Error Code: %s</p>
                <p>Message: %s</p>
            </body></html>
        """%(code, message)
        self.packit_write(code, message, headers, content)
        
    def packit_write(self, code, logs, head, body):
        session, content= encrypt_fast(body)
        chrome= zlib.compress(pickle.dumps([code, logs, head, session]))
        chrome= encrypt_rsa(self.RSA_KEY, chrome)
        self.response.headers["Content-Type"]= "application/octet-stream"
        self.response.headers["X-WP-Version"]= "1.0"
        self.response.headers["X-WP-Offset"]= str(len(chrome))
        self.response.headers["X-WP-Length"]= str(len(body))
        self.response.out.write(chrome+content)
            
    def read_unpack(self):
        if self.request.headers["X-WP-Version"] != "1.0": 
            self.report(430, "client and server version is not the same")
        offset= int(self.request.headers["X-WP-Offset"])
        chrome= decrypt_rsa(self.RSA_KEY, self.request.body[0:offset])
        method, path, headers, session= pickle.loads(zlib.decompress(chrome))    
        content= decrypt_fast(session, self.request.body[offset:])
        if int(self.request.headers["X-WP-Length"]) != len(content):
            self.report(431, "data package is broken in transporting")
        return (method, path, headers, content)            

    def post(self):          
        code= 0; logs="";
        method, url, headers, pdata= self.read_unpack()        
        for h in MainHandler.SKIPHEAD_REQUEST:
            if h in headers: del headers[h];
        headers['connection']= 'close'
        
        for _ in xrange(MainHandler.RETRY_FETCH):
            try:            
                logging.debug("REQ: %s %s\n%s"%(method, url, 
                    "\n".join(["%s: %.60s"%h for h in headers.iteritems()])))
                ret= urlfetch.fetch(url, pdata, method, headers,
                    False, False, 10 if pdata else 5)                
                logging.debug("RSP: %s %s\n%s"%(ret.status_code, ret.final_url, 
                    "\n".join(["%s: %.60s"%h for h in ret.headers.iteritems()])))
                code= code&0xF000|ret.status_code
                logs= logs+ ("\nredirect: %s"%ret.final_url if ret.final_url else "finish")
                head= dict(ret.headers)
                body= ret.content
                break
            except urlfetch.ResponseTooLargeError, ex:
                if method=='GET' and not code&0x1000: 
                    code= 0x1000|code
                    logs= logs+"\ntrying range fetch."
                    headers["range"]= "bytes=0-1000000"
                    continue
                return self.report(440, 'cant process large response(>30MB) w/o GET')                   
            except urlfetch.DownloadError, ex:
                return self.report(441, "target server do not return a status code: %s"%ex)
            except urlfetch.InvalidURLError, ex:
                return self.report(442, 'invalid urlfetch url: %s'% url)
            except urlfetch.InvalidMethodError, ex:
                return self.report(443, 'invalid urlfetch method: %s'% method)            
            except apiproxy_errors.DeadlineExceededError, ex:
                return self.report(540, "maximize deadline limit(10sec) exceeded")
            except apiproxy_errors.OverQuotaError, ex:
                return self.report(541, "application is overquota: %s"% ex)
            except Exception, ex:
                code= 0x2000|code 
                logs= logs+"\nerr:" + str(ex)
                logging.error(str(ex))
                continue
        else: return self.report(543, "fail too many times: %s"% logs)
        
        if 'set-cookie' in head:            
            head["set-cookie"]= re.sub(r', (?=[^,;]+=)', "\r\nset-cookie: ", head["set-cookie"])
        for h in MainHandler.SKIPHEAD_RESPONSE:
            if h in head: del head[h];    
        head['connection']='close'
        return self.packit_write(code, logs, head, body)
        
    def get(self):
        self.response.headers["Content-Type"] = "text/html; charset=utf-8"
        self.response.out.write(r'''
            <html><head>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\
                <title>GAppProxy已经在工作了</title>
            </head><body>
                <table width="800" border="0" align="center">
                    <tr><td align="center"><hr></td></tr>
                    <tr><td align="center">
                        <b><h1>%s 已经在工作了</h1></b>
                    </td></tr>
                    <tr><td align="center"><hr></td></tr>
                    <tr><td align="center">
                        GAppProxy是一个开源的HTTP Proxy软件,使用Python编写,运行于Google App Engine平台上. 
                    </td></tr>
                    <tr><td align="center"><hr></td></tr>
                    <tr><td align="center">
                        更多相关介绍,请参考<a href="http://gappproxy.googlecode.com/">GAppProxy项目主页</a>. 
                    </td></tr>
                    <tr><td align="center"><hr></td></tr>
                    <tr><td align="center">
                        <img src="http://code.google.com/appengine/images/appengine-silver-120x30.gif" alt="Powered by Google App Engine" />
                    </td></tr>
                    <tr><td align="center"><hr></td></tr>
                </table>
            </body></html>
        ''' % self.SERVER_ID)      
        
def main():
    run_wsgi_app(webapp.WSGIApplication([
        (r'/.*', MainHandler)
    ], debug=True))
    
if __name__ == '__main__':
    main()
    
        